package com.pf.utils;

import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;

import java.util.List;
import java.util.Map;

/**
 * @author PanFei
 * @version 1.0.0
 * @createTime 2021/7/28
 */
@Slf4j
public class ElasticSearchUtils {

    private static RestHighLevelClient client = SpringContextUtils.getBean(RestHighLevelClient.class);

    /**
     * 检查elasticSearch中是否已存在索引
     *
     * @param indexName
     * @return true：已存在  false:不存在
     */
    public static boolean isExistingIndex(String indexName) {
        try {
            // 准备request对象
            GetIndexRequest request = new GetIndexRequest(indexName);
            return client.indices().exists(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error(">>>>> ElasticSearchUtils isExistingIndexo error", e);
        }
        return false;
    }

    /**
     * 创建索引
     *
     * @param settings
     * @param mappings
     * @param indexName 索引名称
     * @return true:创建成功  false:创建失败
     */
    public static boolean createIndex(Settings.Builder settings, XContentBuilder mappings, String indexName) {
        try {
            // 将settings和mappings封装成一个request对象
            CreateIndexRequest request = new CreateIndexRequest(indexName);
            if (settings != null) {
                request.settings(settings);
            }
            if (mappings != null) {
                request.mapping(mappings);
            }
            // 创建索引
            CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
            return response.isAcknowledged();
        } catch (Exception e) {
            log.error(">>>>> ElasticSearchUtils createIndex error", e);
        }
        return false;
    }

    /**
     * 删除索引
     *
     * @param indexName
     * @return true:已删除  false:未删除
     */
    public static boolean deleteIndex(String indexName) {
        try {
            DeleteIndexRequest request = new DeleteIndexRequest(indexName);
            AcknowledgedResponse response = client.indices().delete(request, RequestOptions.DEFAULT);
            return response.isAcknowledged();
        } catch (Exception e) {
            log.error(">>>>> ElasticSearchUtils deleteIndex error", e);
        }
        return false;
    }


    /**
     * 批量添加文档数据
     *
     * @param indexName 索引名称
     * @param data      数据信息（key为每条数据的id，value中为每条数据的json字符串）
     */
    public static void batchAddData(String indexName, Map<String, String> data) {
        try {
            if (StringUtils.isBlank(indexName) || data == null || data.size() == 0) {
                return;
            }
            // 批量插入文档数据
            BulkRequest request = new BulkRequest();
            data.forEach((key, value) -> {
                request.add(new IndexRequest().index(indexName).id(key).source(value, XContentType.JSON));
            });
            BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);
            System.out.println(">>>> 花销时间：" + response.getTook());
            System.out.println(">>>> 新增的数据：" + response.getItems());
        } catch (Exception e) {
            log.error(">>>>> ElasticSearchUtils batchAddData error", e);
        }
    }

    /**
     * 返回某索引所有信息
     *
     * @param indexName
     * @return
     */
    public static SearchHits getAllData(String indexName) {
        List<String> targetList = Lists.newArrayList();
        try {
            // 查询所有文档信息
            SearchRequest request = new SearchRequest(indexName);
            // 查询所有的文档信息
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().query(QueryBuilders.matchAllQuery());
            request.source(searchSourceBuilder);
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            log.info(">>>>> ElasticSearchUtils getAllData 查询花费时间：" + response.getTook());
            SearchHits hits = response.getHits();
            if (hits != null) {
                for (SearchHit hit : hits) {
                    targetList.add(hit.getSourceAsString());
                }
            }
            return hits;
        } catch (Exception e) {
            log.error(">>>>> ElasticSearchUtils getAllData error", e);
        }
        log.info(">>>> 查询数据信息：{}", targetList);
        return null;
    }

    /**
     * 批量修改索引的数据
     *
     * @param indexName 索引名称
     * @param data      修改的数据。其中key是数据的id，value是需要修改的数据（为json字符串）
     */
    public static void batchUpdateData(String indexName, Map<String, String> data) {
        try {
            if (StringUtils.isBlank(indexName) || data == null || data.size() == 0) {
                return;
            }
            BulkRequest request = new BulkRequest();
            data.forEach((key, value) -> {
                request.add(new UpdateRequest().index(indexName).id(key).doc(value, XContentType.JSON));
            });
            BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);
            System.out.println(">>>> 花销时间：" + response.getTook());
            System.out.println(">>>> 修改的数据：" + response.getItems());
        } catch (Exception e) {
            log.error(">>>>> ElasticSearchUtils batchUpdateData error", e);
        }
    }

    /**
     * 批量删除数据
     *
     * @param indexName 索引名称
     * @param ids       索引数据id
     */
    public static void batchDeleteData(String indexName, List<String> ids) {
        try {
            if (StringUtils.isBlank(indexName) || ids == null || ids.size() == 0) {
                return;
            }
            BulkRequest request = new BulkRequest();
            for (String id : ids) {
                request.add(new DeleteRequest(indexName).id(id));
            }
            BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);
            System.out.println(">>>> 花销时间：" + response.getTook());
            System.out.println(">>>> 修改的数据：" + response.getItems());
        } catch (Exception e) {
            log.error(">>>>> ElasticSearchUtils batchDeleteData error", e);
        }
    }

    /**
     * 通过查询条件查询
     *
     * @param indexName     索引名称
     * @param params        查询条件 key为查询参数名，value为查询参数值
     * @param descSortField 倒叙排序字段
     * @return
     */
    public static SearchHits queryByParams(String indexName, Map<String, Object> params, String descSortField) {
        try {
            if (StringUtils.isBlank(indexName)) {
                return null;
            }
            SearchRequest request = new SearchRequest(indexName);
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            if (params != null) {
                params.forEach((key, value) -> {
                    boolQueryBuilder.must(QueryBuilders.matchQuery(key, value));
                });
            }

            // 查询条件
            searchSourceBuilder.query(boolQueryBuilder);
            // 排序
            searchSourceBuilder.sort(descSortField, SortOrder.DESC);
            request.source(searchSourceBuilder);
            // 查询
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            SearchHits hits = response.getHits();
            for (SearchHit hit : hits) {
                System.out.println(hit.getSourceAsString());
            }

            return hits;
        } catch (Exception e) {
            log.error(">>>>> ElasticSearchUtils queryByParams error", e);
        }
        return null;
    }
}
